package com.ardf.service.impl;

import com.alibaba.excel.EasyExcel;
import com.ardf.common.EntityConstants;
import com.ardf.entity.Algorithm;
import com.ardf.entity.Group;
import com.ardf.entity.Project;
import com.ardf.entity.Rule;
import com.ardf.entity.dto.DownloadRuleDto;
import com.ardf.entity.dto.RuleInfoDto;
import com.ardf.entity.dto.RuleProjectMenuDto;
import com.ardf.entity.dto.RuleTableDto;
import com.ardf.entity.vo.RuleUpdateVo;
import com.ardf.mapper.AlgorithmMapper;
import com.ardf.mapper.GroupMapper;
import com.ardf.mapper.ProjectMapper;
import com.ardf.mapper.RuleMapper;
import com.ardf.service.IRuleService;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import jakarta.servlet.http.HttpServletResponse;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.StringUtils;

import java.io.IOException;
import java.net.URLEncoder;
import java.nio.charset.StandardCharsets;
import java.time.LocalTime;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.StringJoiner;

/**
 * <p>
 * 服务实现类
 * </p>
 *
 * @author ShiYunHao
 * @since 2025-01-06
 */
@Service
public class RuleServiceImpl extends ServiceImpl<RuleMapper, Rule> implements IRuleService {

    private final ProjectMapper projectMapper;
    private final RuleMapper ruleMapper;
    private final AlgorithmMapper algorithmMapper;
    private final GroupMapper groupMapper;

    public RuleServiceImpl(ProjectMapper projectMapper, RuleMapper ruleMapper, AlgorithmMapper algorithmMapper,
                           GroupMapper groupMapper) {
        this.projectMapper = projectMapper;
        this.ruleMapper = ruleMapper;
        this.algorithmMapper = algorithmMapper;
        this.groupMapper = groupMapper;
    }

    /**
     * 通过id获得项目名
     */
    private String getProjectNameByProjectId(Long projectId) {
        Map<Byte, String> projectType = Map.of(EntityConstants.PROJECT_TYPE_FAST, "快速",
                EntityConstants.PROJECT_TYPE_MEDIUM, "中距离",
                EntityConstants.PROJECT_TYPE_SHORT, "短距离",
                EntityConstants.PROJECT_TYPE_SUNLIGHT, "阳光测向",
                EntityConstants.PROJECT_TYPE_STANDARD, "标准距离");
        Map<Byte, String> projectFrequency = Map.of(EntityConstants.PROJECT_FREQUENCY_2m, "2m",
                EntityConstants.PROJECT_FREQUENCY_80m, "80m");
        Map<Byte, String> projectCategory = Map.of(EntityConstants.PROJECT_CATEGORY_PERSON, "个人",
                EntityConstants.PROJECT_CATEGORY_RELAY, "接力");
        Project project = projectMapper.selectById(projectId);
        return projectType.get(project.getType()) + "-" + projectFrequency.get(project.getFrequency()) + "-" +
                projectCategory.get(project.getCategory());
    }

    @Override
    public Page<RuleTableDto> searchAll(Integer pageSize, Integer pageNum, Long competitionId, Long projectId) {
        Page<RuleTableDto> page = new Page<>(pageNum, pageSize);
        Page<RuleTableDto> ruleTableDtoPage = ruleMapper.searchAll(page, competitionId, projectId);
        for (RuleTableDto record : ruleTableDtoPage.getRecords()) {
            record.setProjectName(getProjectNameByProjectId(record.getProjectId()));
            record.setProjectTime(record.getProjectTime());
            record.setAlgorithmTypeName(getAlgorithmTypeNameByType(record.getAlgorithmType()));
        }
        return ruleTableDtoPage;
    }

    /**
     * 根据数据库字段转译成中文
     */
    private String getAlgorithmTypeNameByType(Byte type) {
        if (type != null) {
            Map<Byte, String> algorithmTypeMap = Map.of(EntityConstants.ALGORITHM_TYPE_NO_ORDER, "无顺序",
                    EntityConstants.ALGORITHM_TYPE_ORDER_NO_BACK_FIRST, "有顺序，不能反悔，取第一个站开始算的最长有效子路线",
                    EntityConstants.ALGORITHM_TYPE_ORDER_BACK_EFFECTIVE, "有顺序，能反悔，取最长有效子路线",
                    EntityConstants.ALGORITHM_TYPE_ORDER_NO_BACK_EFFECTIVE, "有顺序，不能反悔，取最长有效子路线",
                    EntityConstants.ALGORITHM_TYPE_RELAY_NO_ORDER, "接力赛无顺序",
                    EntityConstants.ALGORITHM_TYPE_FAST_NO_ORDER, "快速赛无顺序",
                    EntityConstants.ALGORITHM_TYPE_SUNLIGHT_ORDER, "阳光严格有顺序",
                    EntityConstants.ALGORITHM_TYPE_SUNLIGHT_RELAY_ORDER, "阳光接力严格有顺序");
            return algorithmTypeMap.get(type);
        } else {
            return null;
        }
    }

    @Override
    @Transactional
    public void addByBatch(List<Rule> rules) {
        //新增规则表
        ruleMapper.insert(rules);

        for (Rule rule1 : rules) {
            Rule rule = ruleMapper.selectOne(new LambdaQueryWrapper<Rule>()
                    .eq(Rule::getProjectId, rule1.getProjectId())
                    .eq(Rule::getGroupId, rule1.getGroupId()));
            ArrayList<Algorithm> algorithms = new ArrayList<>();
            Project project = projectMapper.selectById(rule.getProjectId());
            if (EntityConstants.PROJECT_TYPE_STANDARD.equals(project.getType())
                    || EntityConstants.PROJECT_TYPE_MEDIUM.equals(project.getType())) {//无顺序个人
                Algorithm algorithm = new Algorithm();
                algorithm.setRuleId(rule.getId());
                algorithm.setType(EntityConstants.ALGORITHM_TYPE_NO_ORDER);
                algorithm.setStatus(EntityConstants.ALGORITHM_STATUS_NO_AGREED_NO_FINAL);
                algorithmMapper.insert(algorithm);
            } else if (EntityConstants.PROJECT_TYPE_SHORT.equals(project.getType())) {//无顺序接力+无顺序个人+有顺序个人3个
                if (EntityConstants.PROJECT_CATEGORY_RELAY.equals(project.getCategory())) {
                    Algorithm algorithm = new Algorithm();
                    algorithm.setType(EntityConstants.ALGORITHM_TYPE_RELAY_NO_ORDER);
                    algorithms.add(algorithm);
                } else {
                    Algorithm algorithm1 = new Algorithm();
                    algorithm1.setType(EntityConstants.ALGORITHM_TYPE_NO_ORDER);
                    algorithms.add(algorithm1);
                    Algorithm algorithm2 = new Algorithm();
                    algorithm2.setType(EntityConstants.ALGORITHM_TYPE_ORDER_BACK_EFFECTIVE);
                    algorithms.add(algorithm2);
                    Algorithm algorithm3 = new Algorithm();
                    algorithm3.setType(EntityConstants.ALGORITHM_TYPE_ORDER_NO_BACK_EFFECTIVE);
                    algorithms.add(algorithm3);
                    Algorithm algorithm4 = new Algorithm();
                    algorithm4.setType(EntityConstants.ALGORITHM_TYPE_ORDER_NO_BACK_FIRST);
                    algorithms.add(algorithm4);
                }
                for (Algorithm algorithm5 : algorithms) {
                    algorithm5.setRuleId(rule.getId());
                    algorithm5.setStatus(EntityConstants.ALGORITHM_STATUS_NO_AGREED_NO_FINAL);
                }
                algorithmMapper.insert(algorithms);

            } else if (EntityConstants.PROJECT_TYPE_FAST.equals(project.getType())) {//无顺序快速
                Algorithm algorithm = new Algorithm();
                algorithm.setStatus(EntityConstants.ALGORITHM_STATUS_NO_AGREED_NO_FINAL);
                algorithm.setRuleId(rule.getId());
                algorithm.setType(EntityConstants.ALGORITHM_TYPE_FAST_NO_ORDER);
                algorithmMapper.insert(algorithm);
            } else if (EntityConstants.PROJECT_TYPE_SUNLIGHT.equals(project.getType())) {//有顺序阳光,接力有顺序阳光
                if (EntityConstants.PROJECT_CATEGORY_RELAY.equals(project.getCategory())) {
                    Algorithm algorithm = new Algorithm();
                    algorithm.setStatus(EntityConstants.ALGORITHM_STATUS_NO_AGREED_NO_FINAL);
                    algorithm.setRuleId(rule.getId());
                    algorithm.setType(EntityConstants.ALGORITHM_TYPE_SUNLIGHT_RELAY_ORDER);
                    algorithms.add(algorithm);
                } else {
                    Algorithm algorithm1 = new Algorithm();
                    algorithm1.setStatus(EntityConstants.ALGORITHM_STATUS_NO_AGREED_NO_FINAL);
                    algorithm1.setRuleId(rule.getId());
                    algorithm1.setType(EntityConstants.ALGORITHM_TYPE_SUNLIGHT_ORDER);
                    algorithms.add(algorithm1);
                }
                algorithmMapper.insert(algorithms);
            } else {
                throw new RuntimeException("批量添加规则错误:找不到对应的项目类型");
            }
        }
    }

    @Override
    @Transactional
    public void deleteByBatch(List<Long> ids) {
        if (ids != null && !ids.isEmpty()) {
            //删除算法表
            algorithmMapper.delete(new LambdaQueryWrapper<Algorithm>()
                    .in(Algorithm::getRuleId, ids));
            //删除规则表
            ruleMapper.deleteByIds(ids);
        }
    }

    @Override
    public List<RuleProjectMenuDto> getProjectMenu(Long competitionId) {
        List<Long> projectIds = projectMapper.selectObjs(new LambdaQueryWrapper<Project>().select(Project::getId)
                .eq(Project::getCompetitionId, competitionId)
                .orderByAsc(Project::getType, Project::getFrequency, Project::getCategory));
        return projectIds.stream().map(projectId -> {
            RuleProjectMenuDto ruleProjectMenuDto = new RuleProjectMenuDto();
            ruleProjectMenuDto.setProjectId(projectId);
            ruleProjectMenuDto.setProjectName(getProjectNameByProjectId(projectId));
            return ruleProjectMenuDto;
        }).toList();
    }

    @Override
    @Transactional
    public void updateRule(RuleUpdateVo ruleUpdateVo) {
        Rule rule = new Rule();
        rule.setId(ruleUpdateVo.getRuleId());
        StringJoiner stringJoiner = new StringJoiner("-");
        for (String s : ruleUpdateVo.getRoute()) {
            stringJoiner.add(s);
        }
        rule.setRoute(stringJoiner.toString());
        String limitTime = ruleUpdateVo.getLimitTime();
        if (StringUtils.hasLength(limitTime)) {
            rule.setLimitTime(LocalTime.parse(limitTime));
        }
        ruleMapper.updateById(rule);
        if (ruleUpdateVo.getAlgorithmId() != null) {
            Algorithm algorithm = algorithmMapper.selectById(ruleUpdateVo.getAlgorithmId());
            if (EntityConstants.ALGORITHM_STATUS_NO_AGREED_NO_FINAL.equals(algorithm.getStatus())) {//当未商定设最终直接改为2
                algorithm.setStatus(EntityConstants.ALGORITHM_STATUS_AGREED_NO_FINAL);
            } else if (EntityConstants.ALGORITHM_STATUS_NO_AGREED_FINAL.equals(algorithm.getStatus())) {//当未商定设最终直接改为1
                algorithm.setStatus(EntityConstants.ALGORITHM_STATUS_AGREED_FINAL);
            }
            //将当前规则id下的所有算法status全改为2
            algorithmMapper.update(new LambdaUpdateWrapper<Algorithm>().eq(Algorithm::getRuleId, algorithm.getRuleId()).set(Algorithm::getStatus, 2));
            algorithmMapper.updateById(algorithm);
        }


    }

    @Override
    public void download(HttpServletResponse response, Long competitionId) throws IOException {
        // 这里注意 有同学反应使用swagger 会导致各种问题，请直接用浏览器或者用postman
        response.setContentType("application/vnd.openxmlformats-officedocument.spreadsheetml.sheet");
        response.setCharacterEncoding("utf-8");
        // 这里URLEncoder.encode可以防止中文乱码 当然和easyexcel没有关系
        String fileName = URLEncoder.encode("比赛规则表", StandardCharsets.UTF_8).replaceAll("\\+", "%20");
        response.setHeader("Content-Disposition", "attachment;filename*=utf-8''" + fileName + ".xlsx");
        List<DownloadRuleDto> list = ruleMapper.getAll(competitionId);
        for (DownloadRuleDto downloadRuleDto : list) {
            if (downloadRuleDto.getAlgorithmType() != null) {
                downloadRuleDto.setAlgorithmTypeName(
                        EntityConstants.ALGORITHM_TYPE_NAME_MAP.get(downloadRuleDto.getAlgorithmType()));
                downloadRuleDto.setAlgorithmDescription(
                        EntityConstants.ALGORITHM_TYPE_DESCRIPTION_MAP.get(downloadRuleDto.getAlgorithmType())
                                .replaceAll("<br>", ""));
            }
            if (downloadRuleDto.getLimitTime() != null) {
                downloadRuleDto.setLimitTimeStr(downloadRuleDto.getLimitTime().toString());
            }
            downloadRuleDto.setProjectName(getProjectNameByProjectId(downloadRuleDto.getProjectId()));
        }
        EasyExcel.write(response.getOutputStream(), DownloadRuleDto.class).sheet("表格1").doWrite(list);
    }

    @Override
    public RuleInfoDto getRuleInfo(Long ruleId) {
        RuleInfoDto ruleInfoDto = new RuleInfoDto();
        Rule rule = ruleMapper.selectById(ruleId);
        Project project = projectMapper.selectById(rule.getProjectId());
        Group group = groupMapper.selectById(rule.getGroupId());
        String projectName = EntityConstants.PROJECT_TYPE_STRING_MAP.get(project.getType()) + "-" +
                EntityConstants.PROJECT_FREQUENCY_STRING_MAP.get(project.getFrequency()) + "-" +
                EntityConstants.PROJECT_CATEGORY_STRING_MAP.get(project.getCategory());
        ruleInfoDto.setProjectName(projectName);
        ruleInfoDto.setGroupName(group.getName());
        ruleInfoDto.setGroupId(group.getId());
        ruleInfoDto.setProjectId(project.getId());
        ruleInfoDto.setIsRelay(EntityConstants.PROJECT_CATEGORY_RELAY.equals(project.getCategory()));
        ruleInfoDto.setStartTime(project.getStartTime());
        ruleInfoDto.setLimitTime(rule.getLimitTime());
        ruleInfoDto.setRoute(rule.getRoute());
        Algorithm algorithm = algorithmMapper.selectOne(new LambdaQueryWrapper<Algorithm>()
                .eq(Algorithm::getRuleId, ruleId)
                .in(Algorithm::getStatus, List.of(EntityConstants.ALGORITHM_STATUS_AGREED_FINAL,
                        EntityConstants.ALGORITHM_STATUS_AGREED_NO_FINAL)));
        if (algorithm != null) {
            ruleInfoDto.setAlgorithmName(EntityConstants.ALGORITHM_TYPE_NAME_MAP.get(algorithm.getType()));
        }
        return ruleInfoDto;
    }
}
